<template>
  <div class="message" :class="{ 'message-user': isUser }">
    <div class="avatar">
      <UserCircleIcon v-if="isUser" class="icon" />
      <ComputerDesktopIcon v-else class="icon" :class="{ 'assistant': !isUser }" />
    </div>
    <div class="content">
      <div class="text-container">
        <button v-if="isUser" class="user-copy-button" @click="copyContent" :title="copyButtonTitle">
          <DocumentDuplicateIcon v-if="!copied" class="copy-icon" />
          <CheckIcon v-else class="copy-icon copied" />
        </button>
        <div class="text" ref="contentRef" v-if="isUser">
          {{ message.content }}
        </div>
        <div class="text markdown-content" ref="contentRef" v-else v-html="processedContent"></div>
      </div>

      <!-- 温度图表区域 - 仅助手消息且有图表数据时显示 -->
      <div v-if="showChart" class="chart-container">
        <canvas ref="chartRef" width="400" height="200"></canvas>
      </div>

      <!-- 生成Word报表按钮 - 仅助手消息且有内容时显示 -->
      <div v-if="!isUser && message.content" class="export-word-btn">
        <el-button
            type="primary"
            size="small"
            @click="generateWordReport"
            :loading="isGeneratingWord"
        >
          生成Word报表
        </el-button>
      </div>

      <div class="message-footer" v-if="!isUser">
        <button class="copy-button" @click="copyContent" :title="copyButtonTitle">
          <DocumentDuplicateIcon v-if="!copied" class="copy-icon" />
          <CheckIcon v-else class="copy-icon copied" />
        </button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed, onMounted, nextTick, ref, watch, onUnmounted } from 'vue';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
import { saveAs } from 'file-saver';
import {
  UserCircleIcon,
  ComputerDesktopIcon,
  DocumentDuplicateIcon,
  CheckIcon
} from '@heroicons/vue/24/outline';
import hljs from 'highlight.js';
import 'highlight.js/styles/github-dark.css';
import { ElMessage } from 'element-plus';

// 引入外部CSS文件
import '@/assets/ChatMessage.css';

// Props定义
const props = defineProps({
  message: {
    type: Object,
    required: true
  }
});


// 引入Chart.js
import {
  Chart,
  LineController,
  LineElement,
  PointElement,
  LinearScale,
  Title,
  CategoryScale,
  Legend,
  Tooltip
} from 'chart.js';
import {chatAPI} from "@/services/api.js";

// 注册Chart组件
Chart.register(
    LineController, LineElement, PointElement,
    LinearScale, Title, CategoryScale, Legend, Tooltip
);

// 组件状态
const contentRef = ref(null);
const copied = ref(false);

const showChart = ref(false);
const chartRef = ref(null);
const chartInstance = ref(null);

const isGeneratingWord = ref(false);


// 计算属性
const isUser = computed(() => props.message.role === 'user');
const copyButtonTitle = computed(() => copied.value ? '已复制' : '复制内容');

//处理llm内容
const processContent = (content) => {
  if (!content) return '';

  // 配置 marked 选项
  marked.setOptions({
    breaks: true,
    gfm: true
  });

  // 图片链接正则：匹配以下三种格式
  // 1. 阿里系域名 mdn.alipayobjects.com
  // 2. 传统图片后缀（jpg/jpeg/png/gif/svg/webp）
  const imgUrlReg = /https?:\/\/mdn\.alipayobjects\.com[^\s"]*|https?:\/\/[^\s"]+\.(jpg|jpeg|png|gif|svg|webp)(\?[^\s"]*)?/gi;

  // 先处理普通文本中的图片链接（非think块内）
  content = content.replace(imgUrlReg, (match) => {
    // 提取Markdown图片语法中的alt文本（如![alt](url)）
    const altMatch = content.match(new RegExp(`!\\[([^\\]]+)\\]\\(${match.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\)`));
    const altText = altMatch ? altMatch[1] : (match.includes('mdn.alipayobjects.com') ? '阿里系图表' : '图片');

    return `<img src="${match}" alt="${altText}" style="max-width:100%;height:auto;margin:8px 0;border-radius:4px;cursor:pointer;" onclick="window.open('${match}', '_blank')"/>`;
  });

  let result = '';
  let isInThinkBlock = false;
  let currentBlock = '';

  // 处理think标签（假设使用```作为块标记，可根据实际标签调整）
  for (let i = 0; i < content.length; i++) {
    // 匹配块开始标记 ```
    if (content.slice(i, i + 3) === '```') {
      isInThinkBlock = true;
      if (currentBlock) {
        result += marked.parse(currentBlock);
      }
      currentBlock = '';
      i += 2; // 跳过已匹配的3个字符（i自增1 + 此处加2）
      continue;
    }

    // 匹配块结束标记 ```
    if (content.slice(i, i + 3) === '```' && isInThinkBlock) {
      isInThinkBlock = false;
      // 处理块内内容的图片链接
      const processedBlock = currentBlock.replace(imgUrlReg, (match) => {
        const altMatch = currentBlock.match(new RegExp(`!\\[([^\\]]+)\\]\\(${match.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\)`));
        const altText = altMatch ? altMatch[1] : (match.includes('mdn.alipayobjects.com') ? '阿里系图表' : '图片');
        return `<img src="${match}" alt="${altText}" style="max-width:100%;height:auto;margin:8px 0;border-radius:4px;cursor:pointer;" onclick="window.open('${match}', '_blank')"/>`;
      });
      result += `<div class="think-block">${marked.parse(processedBlock)}</div>`;
      currentBlock = '';
      i += 2;
      continue;
    }

    currentBlock += content[i];
  }

  // 处理剩余内容（非块内的文本）
  if (currentBlock) {
    // 解析Markdown并拼接结果
    result += isInThinkBlock
        ? `<div class="think-block">${marked.parse(currentBlock)}</div>`
        : marked.parse(currentBlock);
  }

  // 净化HTML：允许img标签及必要属性
  const cleanHtml = DOMPurify.sanitize(result, {
    ADD_TAGS: ['think', 'code', 'pre', 'span', 'img'], // 允许img标签
    ADD_ATTR: ['class', 'language', 'src', 'alt', 'style', 'onclick'], // 允许点击事件
    USE_PROFILES: { html: true } // 启用基础HTML支持
  });

  // 处理代码块复制功能
  const tempDiv = document.createElement('div');
  tempDiv.innerHTML = cleanHtml;

  const preElements = tempDiv.querySelectorAll('pre');
  preElements.forEach(pre => {
    const code = pre.querySelector('code');
    if (code) {
      const wrapper = document.createElement('div');
      wrapper.className = 'code-block-wrapper';

      const copyBtn = document.createElement('button');
      copyBtn.className = 'code-copy-button';
      copyBtn.title = '复制代码';
      copyBtn.innerHTML = `
        <svg xmlns="http://www.w3.org/2000/svg" class="code-copy-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
        </svg>
      `;

      // 复制功能逻辑
      copyBtn.addEventListener('click', () => {
        navigator.clipboard.writeText(code.textContent).then(() => {
          const successMsg = wrapper.querySelector('.copy-success-message');
          if (successMsg) {
            successMsg.style.opacity = '1';
            setTimeout(() => {
              successMsg.style.opacity = '0';
            }, 2000);
          }
        });
      });

      const successMsg = document.createElement('div');
      successMsg.className = 'copy-success-message';
      successMsg.textContent = '已复制!';
      successMsg.style.opacity = '0';
      successMsg.style.transition = 'opacity 0.3s ease';

      wrapper.appendChild(copyBtn);
      wrapper.appendChild(pre.cloneNode(true));
      wrapper.appendChild(successMsg);
      pre.parentNode.replaceChild(wrapper, pre);
    }
  });

  return tempDiv.innerHTML;
};

// 存储提取的图片链接
const extractedImages = ref([]);

// 提取内容中的所有图片链接
const extractImageUrls = (content) => {
  if (!content) return [];

  const imgUrlReg = /https?:\/\/mdn\.alipayobjects\.com[^\s"]*|https?:\/\/[^\s"]+\.(jpg|jpeg|png|gif|svg|webp)(\?[^\s"]*)?/gi;
  const urls = [];
  let match;

  // 使用 exec 来获取所有匹配项及其位置
  while ((match = imgUrlReg.exec(content)) !== null) {
    urls.push(match[0]);
  }

  return [...new Set(urls)]; // 去重
};

// 处理后的内容
const processedContent = computed(() => {
  if (!props.message.content) return '';
  return processContent(props.message.content);
});

// 处理温度数据并显示图表
const handleTemperatureData = (chartData) => {
  // 数据验证：无chartData或格式错误则隐藏图表
  if (!chartData || !chartData.data || !Array.isArray(chartData.data)) {
    showChart.value = false;
    if (chartInstance.value) {
      chartInstance.value.destroy();
      chartInstance.value = null;
    }
    return;
  }

  // 提取数据、样式、标题等信息
  const { data, style, title, type: chartType = 'line', width, height } = chartData;

  // 数据格式校验：确保每个数据项有time、value、group
  const isValidData = data.every(item =>
      item && typeof item === 'object' &&
      'time' in item && 'value' in item && 'group' in item
  );
  if (!isValidData) {
    console.error('无效的图表数据格式');
    showChart.value = false;
    return;
  }

  //🔥数据有效时，显示图表容器
  showChart.value = true;

  // 按group分组数据
  const groupedData = {};
  data.forEach(item => {
    const group = item.group;
    if (!groupedData[group]) groupedData[group] = [];
    groupedData[group].push({
      value: Number(item.value),
      time: item.time
    });
  });

  const groups = Object.keys(groupedData);
  if (groups.length === 0) {
    showChart.value = false;
    return;
  }

  // 准备图表数据集（默认隐藏，悬停显示）
  const datasets = groups.map(group => ({
    label: group,
    data: groupedData[group].map(item => item.value),
    borderColor: getRandomColor(),
    backgroundColor: 'transparent',
    tension: 0.4,
    fill: false,
    // 默认状态隐藏数据点
    pointRadius: 0,         // 正常状态下不显示数据点
    pointHoverRadius: 5,    // 鼠标悬停时显示数据点（大小为5）
    pointHoverBackgroundColor: getRandomColor(), // 悬停时数据点颜色（与线条一致）
    pointHoverBorderWidth: 2, // 悬停时数据点边框宽度
    pointHoverBorderColor: '#fff' // 悬停时数据点边框颜色（白色描边更明显）
  }));

  const labels = groupedData[groups[0]].map(item => item.time);

  // 等待DOM更新完成
  nextTick(() => {
    // 检查canvas元素是否存在且尺寸有效
    if (!chartRef.value) {
      console.error('Canvas元素不存在');
      showChart.value = false;
      return;
    }

    // 检查canvas尺寸是否有效
    if (!chartRef.value.width || !chartRef.value.height) {
      console.error('Canvas尺寸无效');
      showChart.value = false;
      return;
    }

    // 创建图表
    if (chartInstance.value) {
      chartInstance.value.destroy();
    }

    try {
      chartInstance.value = new Chart(chartRef.value, {
        type: chartType,
        data: { labels, datasets },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          interaction: { mode: 'index', intersect: false },
          plugins: {
            legend: { position: 'top', labels: { usePointStyle: true, boxWidth: 6 } },
            title: { display: true, text: title || '设备数据趋势', font: { size: 16 } },
            tooltip: { padding: 10, cornerRadius: 6 }
          },
          scales: {
            y: {
              beginAtZero: false,
              title: { display: true, text: '数值' },
              ticks: { callback: v => `${v}` }
            },
            x: {
              title: { display: true, text: '时间' },
              ticks: { maxRotation: 45, minRotation: 45 }
            }
          },
          animation: { duration: 1000 },
          ...(style || {}) // 合并自定义样式
        }
      });
    } catch (error) {
      console.error('创建图表失败:', error);
      showChart.value = false;
    }
  });
};

// 生成随机颜色
const getRandomColor = () => {
  // 预定义一组适合图表的颜色，避免随机颜色过于相似
  const presetColors = [
    'rgb(75, 192, 192)',
    'rgb(255, 99, 132)',
    'rgb(54, 162, 235)',
    'rgb(255, 206, 86)',
    'rgb(153, 102, 255)',
    'rgb(255, 159, 64)',
    'rgb(231, 233, 237)',
    'rgb(108, 117, 125)'
  ];

  // 随机选择预定义颜色
  return presetColors[Math.floor(Math.random() * presetColors.length)];
};

// 获取图表图片
const getChartImage = async () => {
  if (!chartRef.value || !chartInstance.value) {
    return null;
  }

  await nextTick();
  return chartRef.value.toDataURL('image/png', 0.9);
};

// 生成Word报表
const generateWordReport = async () => {
  isGeneratingWord.value = true;
  try {
    // 1. 等待图表完全渲染完成
    await new Promise(resolve => {
      const checkChartReady = () => {
        if (chartInstance.value && chartRef.value) {
          resolve();
        } else {
          setTimeout(checkChartReady, 100);
        }
      };
      checkChartReady();
    });

    // 2. 获取图表的Base64图片
    let chartBase64 = null;
    if (showChart.value && chartInstance.value) {
      chartBase64 = await getChartImage();
    }

    // 3. 提取内容中的所有图片链接
    const imageUrls = extractImageUrls(props.message.content);

    // 4. 准备要发送给后端的数据
    const wordData = {
      textContent: props.message.content, // 大模型返回的文本
      chartBase64: chartBase64, // 图表的Base64图片（含"data:image/png;base64,"前缀）
      imageUrls: imageUrls // 提取的所有图片链接
    };

    // 5. 调用后端接口生成Word
    const blob = await chatAPI.sendWordRequest(wordData);

    // 6. 下载Word文件
    saveAs(blob, '故障诊断报告.docx'); // file-saver库的方法
    ElMessage.success('Word报表生成成功！');
  } catch (error) {
    console.error('生成Word失败:', error);
    ElMessage.error('生成Word报表失败: ' + error.message);
  } finally {
    isGeneratingWord.value = false;
  }
};

// 代码块复制功能
const setupCodeBlockCopyButtons = () => {
  if (!contentRef.value) return;

  const codeBlocks = contentRef.value.querySelectorAll('.code-block-wrapper');
  codeBlocks.forEach(block => {
    const copyButton = block.querySelector('.code-copy-button');
    const codeElement = block.querySelector('code');
    const successMessage = block.querySelector('.copy-success-message');

    if (copyButton && codeElement) {
      const newCopyButton = copyButton.cloneNode(true);
      copyButton.parentNode.replaceChild(newCopyButton, copyButton);

      newCopyButton.addEventListener('click', async (e) => {
        e.preventDefault();
        e.stopPropagation();
        try {
          await navigator.clipboard.writeText(codeElement.textContent || '');
          if (successMessage) {
            successMessage.classList.add('visible');
            setTimeout(() => successMessage.classList.remove('visible'), 2000);
          }
        } catch (err) {
          console.error('复制代码失败:', err);
        }
      });
    }
  });
};

// 代码高亮
const highlightCode = async () => {
  await nextTick();
  if (contentRef.value) {
    contentRef.value.querySelectorAll('pre code').forEach((block) => {
      hljs.highlightElement(block);
    });
    setupCodeBlockCopyButtons();
  }
};

// 复制内容
const copyContent = async () => {
  try {
    let textToCopy = props.message.content;

    if (!isUser.value && contentRef.value) {
      const tempDiv = document.createElement('div');
      tempDiv.innerHTML = processedContent.value;
      textToCopy = tempDiv.textContent || tempDiv.innerText || '';
    }

    await navigator.clipboard.writeText(textToCopy);
    copied.value = true;
    setTimeout(() => copied.value = false, 3000);
  } catch (err) {
    console.error('复制失败:', err);
  }
};

// 监听消息内容变化
watch(
    () => props.message.content,
    () => {
      if (!isUser.value) {
        highlightCode();
      }
    }
);

// 监听图表数据变化
watch(
    () => props.message.chartData,
    () => {
      if (!isUser.value) {
        handleTemperatureData(props.message.chartData)
      }
    },
    { deep: true } // 深度监听对象内部变化
);

// 生命周期钩子
onMounted(() => {
  if (!isUser.value) {
    highlightCode();
    handleTemperatureData(props.message.chartData)
  }
});

// 在组件卸载时销毁图表实例
watch(() => showChart.value, (newVal) => {
  if (!newVal && chartInstance.value) {
    chartInstance.value.destroy()
    chartInstance.value = null
  }
})
</script>

